package com.expert.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.expert.Mapper.RoleMapper;
import com.expert.Mapper.UserMapper;
import com.expert.constant.RedisKeyConstant;
import com.expert.constant.RegexConstant;
import com.expert.constant.StatusConstant;
import com.expert.constant.MessageConstant;
import com.expert.context.BaseContext;
import com.expert.dto.UpdatePasswordDTO;
import com.expert.dto.UserDTO;
import com.expert.dto.UserLoginDTO;
import com.expert.exception.*;
import com.expert.pojo.Expert;
import com.expert.pojo.Role;
import com.expert.pojo.User;
import com.expert.service.ExpertService;
import com.expert.service.UserService;
import com.expert.util.Captcha;
import com.expert.util.CaptchaUtil;
import com.expert.vo.*;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import java.time.LocalDateTime;
import java.util.Base64;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @ClassName: UserLoginServiceImpl
 * @Author: cxs
 * @Date: 2024/01/18 20:02
 * @Description:
 **/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    CaptchaUtil captchaUtil;
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    RoleMapper roleMapper;
    @Autowired
    ExpertService expertService;

    @Override
    public User login(UserLoginDTO userLoginDTO) {
        String account = userLoginDTO.getAccount();
        String password = userLoginDTO.getPassword();
        //验证码校验
        String codeInDb = (String) redisTemplate.opsForValue().get(RedisKeyConstant.LOGIN_CODE + userLoginDTO.getUUID());
        if (codeInDb == null || !userLoginDTO.getCheckCode().equalsIgnoreCase(codeInDb)) {
            redisTemplate.delete(RedisKeyConstant.LOGIN_CODE + userLoginDTO.getUUID());
            throw new CheckCodeErrorException(MessageConstant.CHECK_CODE_ERROR);
        }
        redisTemplate.delete(RedisKeyConstant.LOGIN_CODE + userLoginDTO.getUUID());
        //用户校验
        User user = getOne(new LambdaQueryWrapper<User>()
                .eq(User::getAccount, account));

        if (user == null) {
            throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
        }

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        boolean flag = encoder.matches(userLoginDTO.getPassword(), user.getPassword());
        if (!flag) {
            throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
        }
        //账号不能登录
        if (user.getStatus().equals(StatusConstant.DISABLE)) {
            throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);
        }
        return user;
    }

    /**
     * 生成Base64验证码
     *
     * @return
     */
    @Override
    public CheckCodeVo createCode() {
        Captcha captcha = captchaUtil.generate(112, 40);
        String code = captcha.getCode();
        Base64.Encoder encoder = Base64.getEncoder();
        String image = encoder.encodeToString(captcha.getImgBytes());
        String uuid = UUID.randomUUID().toString().replace("-", "");
        redisTemplate.opsForValue().set(RedisKeyConstant.LOGIN_CODE + uuid, code, 2, TimeUnit.MINUTES);
        CheckCodeVo checkCodeVo = CheckCodeVo.builder()
                .img(image)
                .uuid(uuid)
                .build();
        return checkCodeVo;
    }

    /**
     * 获取用户信息
     *
     * @param account
     * @return
     */
    @Override
    public User getUserInfo(String account) {
        User user = this.lambdaQuery().eq(User::getAccount, account).one();
        if (user == null) {
            return null;
        }
        User newUser = User.builder()
                .id(user.getId())
                .account(user.getAccount())
                .idNumber(user.getIdNumber())
                .phone(user.getPhone())
                .sex(user.getSex())
                .createTime(user.getCreateTime())
                .name(user.getName())
                .role(user.getRole())
                .build();
        return newUser;
    }

    @Override
    public Page<UserPageVo> pageUsers(int page, int pageSize, String account, String name) {
        Page<User> pages = new Page<>(page, pageSize);
        page(pages, new LambdaQueryWrapper<User>()
                .like(StringUtils.isNotEmpty(account), User::getAccount, account)
                .like(StringUtils.isNotEmpty(name), User::getName, name)
                .orderByAsc(User::getCreateTime)
        );
        Page<UserPageVo> newPage = new Page<>(page, pageSize);
        BeanUtils.copyProperties(pages, newPage);
        //对某些敏感信息和无用信息进行屏蔽
        List<UserPageVo> newRecords = pages.getRecords().stream().map(item -> {
            item.setPassword("");
            item.setCreateUser(null);
            item.setUpdateUser(null);
            Role role = this.roleMapper.selectById(item.getRole());
            UserPageVo userPageVo = new UserPageVo(role.getRoleName());
            BeanUtils.copyProperties(item, userPageVo);
            return userPageVo;
        }).collect(Collectors.toList());
        newPage.setRecords(newRecords);
        return newPage;
    }

    /**
     * 修改用户状态
     *
     * @param id     用户id
     * @param status 状态
     */
    @Override
    public void updateUserStatus(Long id, Integer status) {
        //避免越过前端进行请求将超管用户禁用
        User user = this.lambdaQuery().eq(User::getId, id).one();
        if ("super".equals(user.getName())) {
            throw new UserUpdateException("super用户账号不能修改状态！");
        }
        this.lambdaUpdate().set(User::getStatus, status).eq(User::getId, id).update();
    }

    /**
     * 删除用户信息
     *
     * @param ids 待删除用户的id
     */
    @Override
    @Transactional
    public void deleteUsers(List<Long> ids) {
        List<User> userList = this.lambdaQuery().in(User::getId, ids).list();
        userList.forEach(item -> {
            if ("super".equals(item.getAccount())) {
                throw new UserDeleteException("存在不能删除的用户，如super,请检查！");
            }
            if (item.getIsBind()==1){
                throw  new UserDeleteException("已绑定专家信息，删除失败！");
            }
        });
        this.removeBatchByIds(ids);
    }

    /**
     * 获取id
     *
     * @param id
     * @return
     */
    @Override
    public User getUserById(Long id) {
        User user = this.lambdaQuery().eq(User::getId, id).one();
        if (user != null) {
            user.setPassword("");
        }
        return user;
    }

    /**
     * 修改用户信息
     *
     * @param userDTO
     */
    @Override
    public void updateUserById(UserDTO userDTO) {
        if ("super".equals(userDTO.getAccount())) {
            throw new UpdateException("super用户不能修改");
        }
        User user = this.getById(userDTO.getId());
        BeanUtils.copyProperties(userDTO, user);
        this.update(user, new LambdaQueryWrapper<User>().eq(User::getId, user.getId()));
    }

    /**
     * 重置用户密码
     *
     * @param id
     */
    @Override
    public void resetPassword(Long id) {
        User user = this.lambdaQuery().eq(User::getId, id).one();
        if (user == null || "super".equals(user.getAccount())) {
            throw new UpdateException(MessageConstant.PASSWORD_EDIT_ERROR);
        }
        String password = user.getIdNumber().substring(12);
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String newPassword = encoder.encode(DigestUtils.md5DigestAsHex(password.getBytes()));
        this.lambdaUpdate().set(User::getPassword, newPassword).eq(User::getId, id).update();

    }

    /**
     * 添加新用户
     *
     * @param userDTO
     */
    @Override
    public Long addUser(UserDTO userDTO) {
        User user = this.lambdaQuery().eq(User::getAccount, userDTO.getAccount()).one();
        if (user != null) {
            throw new AddException(MessageConstant.ACCOUNT_IS_FOUND);
        }
        if (userMessageCheck(userDTO)) {
            throw new UpdateException(MessageConstant.USER_ADD_NOT_MATCH);
        }
        User newUser = new User();
        BeanUtils.copyProperties(userDTO, newUser);
        String password = newUser.getIdNumber().substring(12);
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        newUser.setPassword( encoder.encode(DigestUtils.md5DigestAsHex(password.getBytes())));
        //添加时间和用户
        newUser.setCreateUser(BaseContext.getCurrentId());
        newUser.setUpdateUser(BaseContext.getCurrentId());
        newUser.setUpdateTime(LocalDateTime.now());
        newUser.setCreateTime(LocalDateTime.now());
        newUser.setStatus(1);
        if (newUser.getIsBind()==null){
            newUser.setIsBind(0);
        }
        this.save(newUser);
        return newUser.getId();
    }

    /**
     * 查询为绑定的用户
     *
     * @return
     */
    @Override
    public List<RemoteUserVo> selectByName(String name) {
        List<User> userList = this.lambdaQuery().like(User::getName,name).list();
        return userList.stream().map(item -> {
            RemoteUserVo remoteUserVo = new RemoteUserVo();
            BeanUtils.copyProperties(item, remoteUserVo);
            String idNumber = item.getIdNumber();
            remoteUserVo.setIdNumber(idNumber.substring(idNumber.length()-6));
            return remoteUserVo;
        }).collect(Collectors.toList());
    }

    /**
     * 修改密码
     *
     * @param passwordDTO
     */
    @Override
    public void updateUserPassword(UpdatePasswordDTO passwordDTO) {
        Long userId = BaseContext.getCurrentId();
        User user = this.getById(userId);
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        if (!encoder.matches(passwordDTO.getOldPassword(),user.getPassword())){
            throw  new UpdateException("旧密码不正确，修改密码失败");
        }
        if (!StringUtils.isNotEmpty(passwordDTO.getNewPassword())){
            throw  new UpdateException("新密码为空，修改密码失败");
        }
        user.setPassword(encoder.encode(passwordDTO.getNewPassword()));
        user.setUpdateUser(userId);
        user.setUpdateTime(LocalDateTime.now());
        this.updateById(user);
    }

    /**
     * 获取用户首页信息
     *
     * @return
     */
    @Override
    public UserHomeInfoVo getUserHomeInfo() {
        Long userId = BaseContext.getCurrentId();
        User user = this.getById(userId);
        UserHomeInfoVo userHomeInfoVo=new UserHomeInfoVo();
        BeanUtils.copyProperties(user,userHomeInfoVo);
        Role role = this.roleMapper.selectById(user.getRole());
        userHomeInfoVo.setUserRoleName(role.getRoleName());
        Expert expert = this.expertService.lambdaQuery().eq(Expert::getExpertUser, userId).one();
        if (expert!=null){
            ExpertInfoVo infoById = this.expertService.getInfoById(expert.getId());
            userHomeInfoVo.setImgUrl(infoById.getExpertPhotoSrc());
        }
        return userHomeInfoVo;
    }

    /**
     * 校验前端信息，防止越过权限对程序进行操作
     *
     * @param userDTO 前端信息
     * @return true:不符合要求 false:符合要求
     */
    private boolean userMessageCheck(UserDTO userDTO) {
        if (userDTO.getAccount() == null || "".equals(userDTO.getAccount()) || userDTO.getAccount().length() < 5) {
            return true;
        } else if (userDTO.getPhone() == null || "".equals(userDTO.getPhone()) || !userDTO.getPhone().matches(RegexConstant.REGEX_PHONE)) {
            return true;
        } else {
            return userDTO.getSex() == null || userDTO.getName() == null || userDTO.getRole() == null;
        }
    }
}
